package com.gxy.learn.securityauth.auth;

import com.gxy.learn.securityauth.mapper.SysRoleMenuMapper;
import com.gxy.learn.securityauth.vo.SysRoleMenuInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Description(自定义实现当前请求的所属用户的权限信息)
 * 参考 https://www.ktanx.com/blog/p/4929
 * @author: Gao xueyong
 * Create at: 2021/12/14 下午11:43
 */
@Slf4j
@Component
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * 方法返回本次访问需要的权限，可以有多个权限。在上面的实现中如果没有匹配的url直接返回null，也就是没有配置权限的url默认都为白名单，想要换成默认是黑名单只要修改这里即可。
     *
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // 获取url
        FilterInvocation filterInvocation = (FilterInvocation) object;
        String requestUrl = filterInvocation.getRequestUrl();
        // 获取拥有url的角色集合
        List<SysRoleMenuInfoVO> roleInfoByUrl = sysRoleMenuMapper.getRoleInfoByUrl(requestUrl);
        if (CollectionUtils.isEmpty(roleInfoByUrl)) {
            return null;
        }
        String roles = roleInfoByUrl.stream().map(SysRoleMenuInfoVO::getRoleName).collect(Collectors.joining(","));
        log.info("{} 对应的角色。{}", requestUrl, roles);
        if (StringUtils.isBlank(roles)) {
            return null;
        }
        // 自定义角色信息 --> Security的权限格式
        String[] attributes = roles.split(",");
        return SecurityConfig.createList(attributes);
    }

    /**
     * 方法如果返回了所有定义的权限资源，Spring Security会在启动时校验每个ConfigAttribute是否配置正确，不需要校验直接返回null。
     *
     * @return
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }
}
